import api from "../../utils/api.js";
import apiConfig from "../../utils/api.js";

Page({
  data: {
    gender: "",
    imgBaseUrl: "",
    MAPI_BASE: apiConfig.ENV.MAPI_BASE,
    activeTab: "story",
    speechText:
      '想解锁属于你的"652"故事吗？我可以基于 652 精神，为你创作一段独特的故事篇章！',
    websocket: null,
    isConnected: false,
    userId: "",
    userToken: "",
    sessionId: "",
    currentReply: "",
    isTyping: false,
    // 视频配置
    currentVideoSrc: "",
    storyRecord: "",
    storyMore: "",
    // 展示相关
    displayTitle: "精选老故事",
    displayStoryList: [],
    displayPhotoList: [],
    displayBookList: [],
    robotAvatar: "",
    // 播放器状态（故事朗读）
    storyAudioLoading: false,

    // 老故事数据
    storyList: [{ id: 0, title: "" }],
    currentVideoState: "default",
    // AI生成故事相关
    promptSuggestions: ["爱情", "科研", "体育", "歌唱"],
    userInput: "",
    generatedStories: [],
    isGenerating: false,
    recording: false,
    isTranscribing: false,
    // 新增：模态数据
    storyModal: {
      show: false,
      index: 0,
      data: { id: null, title: "", content: "", audio: "" },
      isPlaying: false,
    },

    // 聊天相关数据
    messages: [],
    inputValue: "",
    isSending: false,
    showTimeDivider: true,
    currentTime: "",
    isLoading: false,
    scrollTop: 0,
    // 语音播放相关数据
    audioContext: null,
    isPlaying: false,
    // 语音识别相关数据
    isVoiceMode: false, // 是否为语音模式
    recordStartTime: 0, // 录音开始时间
    recordTimer: null, // 录音定时器
    recordManager: null, // 录音管理器
    // 性别角色相关数据
    voiceType: 5003, // 男性声音类型
  },
  // 切换背景视频资源
  switchVideoSource(videoType) {
    const { gender, currentVideoState } = this.data;
    const videoBaseUrl = apiConfig.ENV.videoBaseUrl;
    if (currentVideoState === "idle" && videoType === "speaking") {
      console.log("当前处于idle状态，阻止切换到speaking状态");
      return;
    }
    let videoSrc = "";
    switch (videoType) {
      case "speaking":
        // 语音合成播放时的视频
        videoSrc =
          gender === "male"
            ? videoBaseUrl + "male_speaking.mp4"
            : videoBaseUrl + "female_speaking1.mp4";
        break;
      case "idle":
        // 空闲状态视频（30秒无操作）
        videoSrc =
          gender === "male"
            ? videoBaseUrl + "male_sratching.mp4"
            : videoBaseUrl + "female-scratching1.mp4";
        break;
      case "default":
      default:
        // 默认视频
        videoSrc =
          gender === "male"
            ? videoBaseUrl + "male-waving1.mp4"
            : videoBaseUrl + "female_waving2.mp4";
        break;
    }

    // 更新视频源和当前状态
    this.setData({
      currentVideoSrc: videoSrc,
      currentVideoState: videoType,
    });

    // 延迟一小段时间确保视频源更新后再播放
    setTimeout(() => {
      if (this.videoContext) {
        this.videoContext.seek(0);
        this.videoContext.play();
      }
    }, 100);
  },
  updateCurrentTime() {
    const now = new Date();
    const timeString = now.toLocaleTimeString("zh-CN", {
      hour: "2-digit",
      minute: "2-digit",
    });
    this.setData({
      currentTime: timeString,
    });
  },
  initTimeDisplay() {
    // 立即设置一次时间
    this.updateCurrentTime();

    // 每分钟更新一次时间
    this.timeUpdateInterval = setInterval(() => {
      this.updateCurrentTime();
    }, 60000);
  },
  // 建立WebSocket连接
  connectWebSocket() {
    const { userId } = this.data;
    const wsUrl = api.WS_URL;

    if (this.data.websocket) {
      this.data.websocket.close();
      this.setData({ websocket: null, isConnected: false });
    }

    const websocket = wx.connectSocket({
      url: wsUrl,
      header: api.mapiHeaders,
      method: "GET",
    });

    this.setData({ websocket });

    websocket.onOpen(() => {
      console.log("WebSocket连接已建立");
      this.setData({ isConnected: true });

      const signInCmd = `SignIn ${userId}`;
      websocket.send({
        data: signInCmd,
        success: () => console.log(`已发送SignIn命令：${signInCmd}`),
        fail: (err) => {
          console.error("SignIn命令发送失败：", err);
          // 发送失败时取消生成模式
          this.setData({ isGenerating: false });
          wx.showToast({
            title: "连接认证失败",
            icon: "none",
          });
        },
      });
    });

    websocket.onMessage((res) => {
      const message = res.data;
      console.log(`收到WebSocket消息：${message}`);
      this.handleWebSocketMessage(message);
    });

    websocket.onClose((res) => {
      console.log("WebSocket连接已关闭", res);
      this.setData({
        isConnected: false,
        websocket: null,
      });
      // const app = getApp();
      // if (!app.globalData.isUnloaded) {
      //   setTimeout(() => this.connectWebSocket(), 3000);
      // }
    });

    websocket.onError((err) => {
      console.error("WebSocket错误:", err);
      this.setData({ isConnected: false, isGenerating: false });
      wx.showToast({
        title: "连接失败，请检查网络",
        icon: "none",
      });
    });
  },

  // 处理WebSocket消息
  handleWebSocketMessage(message) {
    console.log(message);
    const { websocket, userId } = this.data;

    if (message.startsWith("SignIn ")) {
      if (message.includes("SignIn OK")) {
        console.log("SignIn验证成功，发送AttachChat命令");
        const attachChatCmd = `AttachChat ${userId}`;
        websocket.send({
          data: attachChatCmd,
          success: () => console.log(`已发送AttachChat命令：${attachChatCmd}`),
        });
      } else {
        console.error("SignIn验证失败：", message);
      }
      return;
    }

    if (message.startsWith("AttachChat ")) {
      if (message.includes("AttachChat OK")) {
        console.log("AttachChat订阅成功");
      } else {
        console.error("AttachChat订阅失败：", message);
      }
      return;
    }

    // ✅ 核心：流式接收 AI 输出
    if (message.startsWith("ChatResult")) {
      try {
        const commandPrefix = "ChatResult ";
        const afterPrefix = message.slice(commandPrefix.length);
        const spaceIndex = afterPrefix.indexOf(" ");
        if (spaceIndex === -1) throw new Error(`消息格式错误：${afterPrefix}`);

        const status = afterPrefix.slice(0, spaceIndex);
        const jsonStr = afterPrefix.slice(spaceIndex + 1);
        if (status !== "OK") {
          // 处理错误状态，如未登录等情况
          if (jsonStr) {
            try {
              const errorData = JSON.parse(jsonStr);
              if (errorData.result === "UNLOGIN") {
                // 未登录情况，取消生成模式并提示用户
                this.setData({ isGenerating: false });
                wx.showToast({
                  title: errorData.reason || "请先登录",
                  icon: "none",
                });
                return;
              }
            } catch (parseError) {
              console.warn("解析错误信息失败：", parseError);
            }
          }
          return console.warn(`AI返回状态异常：${status}`);
        }

        const chatData = JSON.parse(jsonStr);
        const content = (chatData.content || "").toString();
        const isEnd = chatData.isEnd === true;
        const order = chatData.order || 0;

        // 初始化用于存储消息片段的对象（如果尚未初始化）
        if (!this.replyFragments) {
          this.replyFragments = {};
        }

        // === 开始回复 ===
        if (order === 0) {
          this.replyFragments = {}; // 重置片段存储
          this.currentReply = "";
          const updatedMessages = [
            ...this.data.messages,
            {
              role: "robot",
              content: "",
              time: new Date().toLocaleTimeString(),
            },
          ];
          this.setData({ messages: updatedMessages, isTyping: true });

          // 🎬 启动人物动画
          this.startCharacterAnimation();

          // 初始化语音播放相关变量
          this.clearAudioQueue(); // 清空之前的音频队列，确保新对话的独立性

          // 重置片段计数器
          this.segmentCounter = 0;
        }

        // 存储片段按order排序
        this.replyFragments[order] = content;

        // 按顺序重建完整回复
        let reconstructedReply = "";
        const sortedOrders = Object.keys(this.replyFragments)
          .map(Number)
          .sort((a, b) => a - b);
        
        for (const ord of sortedOrders) {
          if (this.replyFragments[ord]) {
            reconstructedReply += this.replyFragments[ord];
          }
        }

        this.currentReply = reconstructedReply;

        const messages = this.data.messages;
        const lastIndex = messages.length - 1;
        if (lastIndex >= 0 && messages[lastIndex].role === "robot") {
          messages[lastIndex].content = this.currentReply;
          this.setData({ messages });
        }

        this.scrollToBottom();

        // === 在回复过程中就开始语音播放 ===
        this.processReplyForTTS(content);

        // === 回复结束 ===
        if (isEnd) {
          this.setData({ isTyping: false });
          const replyLen = this.currentReply.length;

          // 保存回复内容
          const finalReply = this.currentReply;
          this.currentReply = "";
          this.replyFragments = {}; // 清空片段存储

          // 处理剩余的缓冲区内容
          this.processRemainingTTSBuffer();

          // 创建新故事对象
          const newStory = {
            id: Date.now(),
            title: this.data.userInput.trim(),
            content: finalReply,
            createTime: new Date().toLocaleString(),
          };

          // 将新生成的故事添加到列表开头
          const updatedStories = [newStory, ...this.data.generatedStories];

          this.setData({
            generatedStories: updatedStories,
            displayStoryList: updatedStories.slice(0, 3).map((item) => ({
              ...item,
              desc: item.content.substring(0, 50) + "...",
            })),
            userInput: "", // 清空输入框
            currentReply: "",
            isGenerating: false,
          });

          // 确保在AI回复完成后立即进行语音合成播放
          if (finalReply) {
            // 延迟一小段时间确保界面更新完成后再播放语音
            setTimeout(() => {
              this.speakText(finalReply);
            }, 300);
          }

          if (replyLen > 50) {
            this.loopCharacterAnimationOnce();
          } else {
            // 文本输出完成后继续播放视频直到所有音频播放完成
            // 不再立即停止视频，而是等待所有音频播放完成
          }
        }
      } catch (error) {
        console.error("解析ChatResult失败：", error);
        // 发生错误时取消生成模式
        this.setData({ isGenerating: false });
        wx.showToast({
          title: "消息解析失败",
          icon: "none",
        });
      }
      return;
    }

    console.warn("收到未知类型的WebSocket消息：", message);
  },
  speakAIReply(text) {
    if (!text || text.length === 0) {
      console.warn("没有文本内容用于语音合成");
      return;
    }

    // 文本预处理：将652替换为六五二
    const processedText = this.preprocessText(text);

    // 直接调用TTS API并播放
    const { userToken, voiceType } = this.data;

    wx.request({
      url: `${apiConfig.ENV.MAPI_BASE}Helper/Aip/CreateShortTts`,
      method: "POST",
      timeout: 10000,
      header: {
        ...api.mapiHeaders(userToken, { ApiVersion: "5.0" }),
      },
      data: {
        text: processedText,
        voice: voiceType,
        type: "Baidu",
        format: "mp3",
      },
      success: (res) => {
        if (res.data && res.data.base64) {
          // 语音合成成功，立即播放
          this.playAudioFromBase64(res.data.base64, "mp3", () => {
            console.log("AI回复语音播放完成");
          });
        } else {
          console.error("语音合成失败：", res.data);
        }
      },
      fail: (err) => {
        console.error("语音合成请求失败：", err);
      },
    });
  },
  // 处理回复内容用于语音播放
  processReplyForTTS(newContent) {
    if (!newContent || newContent.length === 0) return;

    // 将新内容添加到缓冲区
    if (!this.ttsBuffer) {
      this.ttsBuffer = "";
    }
    this.ttsBuffer += newContent;

    // 定期清理临时文件，避免存储空间耗尽
    this.checkAndCleanStorage();

    // 定义句子结束标点符号
    const sentenceEndings = ["。", "！", "？", "\n", "，"];

    // 检查缓冲区中是否有完整的句子
    while (true) {
      let sentenceEndIndex = -1;

      // 查找第一个句子结束符的位置
      for (let i = 0; i < this.ttsBuffer.length; i++) {
        if (sentenceEndings.includes(this.ttsBuffer[i]) && i > 15) {
          sentenceEndIndex = i;
          break;
        }
      }

      // 如果找到了句子结束符
      if (sentenceEndIndex !== -1) {
        // 提取完整的句子（包括结束符）
        const sentence = this.ttsBuffer.substring(0, sentenceEndIndex + 1);
        this.ttsBuffer = this.ttsBuffer.substring(sentenceEndIndex + 1);

        // 处理这个句子
        this.processTTSSegment(sentence);
      } else {
        // 没有找到句子结束符，检查缓冲区是否太长
        if (this.ttsBuffer.length > 100) {
          // 如果缓冲区太长（超过100字符），强制分割
          const segment = this.ttsBuffer.substring(0, 100);
          this.ttsBuffer = this.ttsBuffer.substring(100);
          this.processTTSSegment(segment);
        } else {
          // 缓冲区不够长，等待更多内容
          break;
        }
      }
    }
  },

  // 处理剩余的缓冲区内容（在回复结束时调用）
  processRemainingTTSBuffer() {
    if (this.ttsBuffer && this.ttsBuffer.length > 0) {
      // 处理剩余的所有文本
      this.processTTSSegment(this.ttsBuffer);
      this.ttsBuffer = ""; // 清空缓冲区
    }
  },

  // 检查是否还有待播放的音频片段
  hasPendingAudioSegments() {
    if (!this.pendingSegments || this.pendingSegments.length === 0) {
      return false;
    }

    // 检查是否有未播放完的片段
    return this.pendingSegments.some((segment) => !segment.isPlayed);
  },

  // 处理单段文本的语音合成
  processTTSSegment(segment) {
    // 文本预处理：将652替换为六五二
    const processedSegment = segment.replace(/652/g, "六五二");

    const { userToken, voiceType } = this.data;

    // 为每个片段分配唯一ID，确保顺序播放
    // 使用递增的计数器确保严格顺序
    if (typeof this.segmentCounter === "undefined") {
      this.segmentCounter = 0;
    }
    this.segmentCounter++;
    const segmentId = this.segmentCounter; // 确保时间戳部分不会影响顺序

    // 创建一个待处理的片段对象（只在需要时创建）
    if (!this.pendingSegments) {
      this.pendingSegments = [];
    }

    // 检查是否已存在相同的片段（避免重复处理）
    const existingSegment = this.pendingSegments.find(
      (s) => s.segment === processedSegment && !s.base64
    );
    if (existingSegment) {
      return; // 避免重复处理相同的片段
    }

    const pendingSegment = {
      id: segmentId,
      segment: processedSegment,
      base64: null,
      isPlaying: false,
      isPlayed: false,
    };

    this.pendingSegments.push(pendingSegment);

    // 调用短文本语音合成API
    this.callTTSAPI(processedSegment, userToken, 0, segmentId, voiceType);
  },

  // 调用TTS API，支持重试机制
  callTTSAPI(segment, userToken, retryCount, segmentId, voiceType = 0) {
    const maxRetries = 2; // 减少重试次数以降低资源消耗

    wx.request({
      url: "https://test.uu163yun.com/mapi/Helper/Aip/CreateShortTts",
      method: "POST",
      timeout: 10000, // 恢复到10秒超时
      header: {
        ...api.mapiHeaders(userToken, { ApiVersion: "5.0" }),
      },
      data: {
        text: segment,
        voice: voiceType, // 使用当前角色的声音类型
        type: "Baidu",
        format: "mp3",
      },
      success: (res) => {
        // 只要返回了base64数据就进行播放，不检查format字段
        if (res.data && res.data.base64) {
          // 语音合成成功，将base64数据添加到播放队列

          // 找到对应的片段并更新其base64数据
          if (this.pendingSegments) {
            console.log(this.pendingSegments);
            const targetSegment = this.pendingSegments.find(
              (s) => s.id === segmentId
            );
            if (targetSegment) {
              targetSegment.base64 = res.data.base64;

              // 尝试播放队列中的下一个音频
              this.tryPlayNextSegment();
            }
          }
        } else if (res.data && res.data.result && res.data.reason) {
          // 处理API错误响应
          console.error("语音合成失败：", res.data.reason);
          // 如果是超时并且还有重试次数，则进行重试
          if (
            (res.data.reason.includes("超时") ||
              res.data.reason.includes("timeout")) &&
            retryCount < maxRetries
          ) {
            setTimeout(() => {
              this.callTTSAPI(
                segment,
                userToken,
                retryCount + 1,
                segmentId,
                voiceType
              );
            }, 500 * (retryCount + 1)); // 减少延迟重试时间
          }
        } else if (res.data && res.data.result === "exception") {
          // 特别处理操作超时等异常
          console.error("语音合成异常：", res.data.reason || "操作超时");
          // 如果是超时并且还有重试次数，则进行重试
          if (
            ((res.data.reason && res.data.reason.includes("超时")) ||
              (res.data.reason && res.data.reason.includes("timeout"))) &&
            retryCount < maxRetries
          ) {
            setTimeout(() => {
              this.callTTSAPI(
                segment,
                userToken,
                retryCount + 1,
                segmentId,
                voiceType
              );
            }, 500 * (retryCount + 1)); // 减少延迟重试时间
          }
        }
      },
      fail: (err) => {
        console.error("语音合成请求失败：", err);
        // 如果还有重试次数，则进行重试
        if (retryCount < maxRetries) {
          setTimeout(() => {
            this.callTTSAPI(
              segment,
              userToken,
              retryCount + 1,
              segmentId,
              voiceType
            );
          }, 500 * (retryCount + 1)); // 减少延迟重试时间
        }
      },
    });
  },

  // 尝试播放队列中的下一个音频片段
  tryPlayNextSegment() {
    if (!this.pendingSegments || this.pendingSegments.length === 0) {
      // 检查是否所有音频都播放完了，如果是则停止视频
      if (!this.hasPendingAudioSegments()) {
        this.stopCharacterAnimation();
      }
      return;
    }

    // 按照添加到队列的顺序查找第一个未播放且已有base64数据的片段
    // 确保严格按照ID顺序播放
    const sortedSegments = this.pendingSegments
      .filter((s) => s.base64 && !s.isPlaying && !s.isPlayed)
      .sort((a, b) => a.id - b.id);

    // 获取ID最小的片段
    const nextSegment = sortedSegments.length > 0 ? sortedSegments[0] : null;

    if (nextSegment && !this.isAudioPlaying) {
      this.isAudioPlaying = true;
      nextSegment.isPlaying = true;
      console.log(nextSegment);
      // 播放音频
      this.playAudioFromBase64(nextSegment.base64, "mp3", () => {
        // 标记为已播放
        nextSegment.isPlayed = true;
        nextSegment.isPlaying = false;
        this.isAudioPlaying = false;

        // 检查是否还有待播放的音频
        if (this.hasPendingAudioSegments()) {
          // 继续尝试播放下一个片段
          this.tryPlayNextSegment();
        } else {
          // 所有音频播放完毕，停止视频
          this.stopCharacterAnimation();
        }
      });
    }
  },

  // 从base64数据播放音频
  playAudioFromBase64(base64Data, format, onComplete) {
    if (!base64Data) {
      console.warn("Base64音频数据为空");
      if (onComplete) onComplete();
      return;
    }

    // 检查base64数据是否有效
    if (base64Data.length < 100) {
      console.warn("Base64音频数据可能无效");
      wx.showToast({
        title: "音频数据无效",
        icon: "none",
      });
      if (onComplete) onComplete();
      return;
    }

    // 开始播放语音时切换到说话视频
    this.switchVideoSource("speaking");

    // 检查存储空间并在必要时清理旧文件
    this.checkAndCleanStorage();

    try {
      // 将base64转换为临时文件
      const fs = wx.getFileSystemManager();
      const fileExtension =
        format && format.toLowerCase() === "wav" ? "wav" : "mp3";
      const filePath = `${
        wx.env.USER_DATA_PATH
      }/temp_audio_${Date.now()}_${Math.floor(
        Math.random() * 1000
      )}.${fileExtension}`;

      fs.writeFile({
        filePath: filePath,
        data: base64Data,
        encoding: "base64",
        success: () => {
          console.log("临时音频文件写入成功:", filePath);
          // 监听音频播放完成事件
          const onEnded = () => {
            this.data.audioContext.offEnded(onEnded);
            console.log("音频播放完成");

            // 音频播放完成，切换回默认视频（不是idle视频）
            this.switchVideoSource("default");

            // 播放完成后删除临时文件
            try {
              fs.unlinkSync(filePath);
              console.log("已删除");
            } catch (e) {
              console.warn("删除临时音频文件失败:", e);
            }
            if (onComplete) onComplete();
          };

          this.data.audioContext.onEnded(onEnded);

          // 播放音频
          this.data.audioContext.src = filePath;
          this.data.audioContext.play();
        },
        fail: (err) => {
          console.error("写入临时音频文件失败：", err);
          // 如果是因为存储空间不足，尝试清理后再重试一次
          if (err.errMsg && err.errMsg.includes("storage limit")) {
            this.cleanTemporaryFiles();
            // 重试一次
            setTimeout(() => {
              fs.writeFile({
                filePath: filePath,
                data: base64Data,
                encoding: "base64",
                success: () => {
                  console.log("临时音频文件写入成功:", filePath);
                  // 监听音频播放完成事件
                  const onEnded = () => {
                    this.data.audioContext.offEnded(onEnded);
                    console.log("音频播放完成");

                    // 音频播放完成，切换回默认视频（不是idle视频）
                    this.switchVideoSource("default");

                    // 播放完成后删除临时文件
                    try {
                      fs.unlinkSync(filePath);
                    } catch (e) {
                      console.warn("删除临时音频文件失败:", e);
                    }
                    if (onComplete) onComplete();
                  };

                  this.data.audioContext.onEnded(onEnded);

                  // 播放音频
                  this.data.audioContext.src = filePath;
                  this.data.audioContext.play();
                },
                fail: (err2) => {
                  console.error("第二次尝试写入临时音频文件也失败了：", err2);
                  this.forceCleanAllTemporaryFiles();
                  if (onComplete) onComplete();
                },
              });
            }, 100);
          } else {
            if (onComplete) onComplete();
          }
        },
      });
    } catch (e) {
      console.error("处理音频数据时发生异常：", e);
      wx.showToast({
        title: "音频处理失败",
        icon: "none",
      });
      if (onComplete) onComplete();
    }
  },
  initIdleDetection() {
    // 清除之前的定时器
    if (this.idleTimer) {
      clearTimeout(this.idleTimer);
    }

    // 设置30秒空闲检测
    this.idleTimer = setTimeout(() => {
      // 检查当前是否正在播放音频，如果没有正在播放音频才触发空闲状态
      const isAudioPlaying = this.data.audioContext && !this.data.audioContext.paused;
      
      // 只有在没有音频播放且不是空闲状态时才触发
      if (!isAudioPlaying && this.data.currentVideoState !== "idle") {
        // 切换到空闲状态视频
        this.switchVideoSource("idle");

        // 添加机器人提示消息
        const idleMessage = "你有没有什么想听的故事呢？";
        const updatedMessages = [
          ...this.data.messages,
          {
            role: "robot",
            content: idleMessage,
            time: new Date().toLocaleTimeString(),
          },
        ];

        this.setData({
          messages: updatedMessages,
        });

        // 滚动到底部
        this.scrollToBottom();

        // 语音播放提示
        this.speakText(idleMessage);
      }

      // 重新启动空闲检测，实现循环检测
      this.initIdleDetection();
    }, 30000); // 30秒
  },

  resetIdleDetection() {
    // 清除空闲定时器
    if (this.idleTimer) {
      clearTimeout(this.idleTimer);
    }

    // 当用户有操作时，将视频状态重置为default
    this.setData({
      currentVideoState: "default",
    });

    // 重新启动空闲检测
    this.initIdleDetection();
  },
  onInput(e) {
    this.setData({
      userInput: e.detail.value,
    });

    // 用户有输入操作，重置空闲检测
    this.resetIdleDetection();
    
    // 用户有新输入时，打断之前的任务
    this.interruptCurrentTask();
  },

  // 选择建议提示词
  selectSuggestion(e) {
    const suggestion = e.currentTarget.dataset.suggestion;
    this.setData({
      userInput: suggestion,
    });

    // 用户选择了建议提示词，重置空闲检测
    this.resetIdleDetection();
    
    // 用户有新输入时，打断之前的任务
    this.interruptCurrentTask();
  },
  
  // 打断当前任务的方法
  interruptCurrentTask() {
    // 停止当前音频播放
    if (this.data.audioContext) {
      try {
        this.data.audioContext.stop();
      } catch (e) {
        console.warn("停止音频播放失败:", e);
      }
    }
    
    // 清空音频队列
    this.clearAudioQueue();
    
    // 删除所有临时音频文件
    this.cleanAllTemporaryFiles();
    
    // 停止视频动画
    this.stopCharacterAnimation();
  },
  
  // 清理所有临时音频文件（不仅仅是过期的）
  cleanAllTemporaryFiles() {
    try {
      const fs = wx.getFileSystemManager();
      const fileList = fs.readdirSync(wx.env.USER_DATA_PATH);
      
      // 删除所有临时音频文件
      fileList.forEach((file) => {
        if (file.startsWith("temp_audio_")) {
          const filePath = `${wx.env.USER_DATA_PATH}/${file}`;
          try {
            fs.unlinkSync(filePath);
            console.log("已删除临时音频文件:", filePath);
          } catch (e) {
            console.warn("删除临时音频文件失败:", filePath, e);
          }
        }
      });
    } catch (e) {
      console.warn("清理临时音频文件时出错:", e);
    }
  },

  // 检查并清理存储空间
  checkAndCleanStorage() {
    if (!this.lastCleanTime || Date.now() - this.lastCleanTime > 15000) {
      this.cleanTemporaryFiles();
      this.lastCleanTime = Date.now();
    }
  },

  // 清理临时音频文件
  cleanTemporaryFiles() {
    try {
      const fs = wx.getFileSystemManager();
      const fileList = fs.readdirSync(wx.env.USER_DATA_PATH);

      // 删除旧的临时音频文件
      fileList.forEach((file) => {
        if (file.startsWith("temp_audio_")) {
          const filePath = `${wx.env.USER_DATA_PATH}/${file}`;
          try {
            const stat = fs.statSync(filePath);
            // 删除超过30秒的临时文件（原来是1分钟，现在改为30秒以更积极地清理）
            if (stat.isFile() && Date.now() - stat.lastAccessedTime > 30000) {
              fs.unlinkSync(filePath);
              console.log("已删除旧的临时音频文件:", filePath);
            }
          } catch (e) {
            console.warn("检查或删除临时文件失败:", filePath, e);
          }
        }
      });
    } catch (e) {
      console.warn("清理临时文件时出错:", e);
    }
  },

  // 强制清理所有临时音频文件（用于存储空间严重不足的情况）
  forceCleanAllTemporaryFiles() {
    try {
      const fs = wx.getFileSystemManager();
      const fileList = fs.readdirSync(wx.env.USER_DATA_PATH);

      // 删除所有临时音频文件
      fileList.forEach((file) => {
        if (file.startsWith("temp_audio_")) {
          const filePath = `${wx.env.USER_DATA_PATH}/${file}`;
          try {
            fs.unlinkSync(filePath);
            console.log("强制删除临时音频文件:", filePath);
          } catch (e) {
            console.warn("强制删除临时文件失败:", filePath, e);
          }
        }
      });
    } catch (e) {
      console.warn("强制清理临时文件时出错:", e);
    }
  },

  // 清空音频队列，实现伪打断功能
  clearAudioQueue() {
    // 清空待处理的文本片段
    if (this.pendingSegments) {
      this.pendingSegments = [];
    }

    // 重置缓冲区
    if (this.ttsBuffer) {
      this.ttsBuffer = "";
    }

    // 停止所有活跃的音频上下文
    if (this.activeAudioContexts) {
      this.activeAudioContexts.forEach((context) => {
        try {
          context.stop();
          context.destroy();
        } catch (e) {
          console.warn("停止音频上下文时出错:", e);
        }
      });
      this.activeAudioContexts = [];
    }

    // 重置播放状态
    this.isAudioPlaying = false;

    // 重置片段计数器
    this.segmentCounter = 0;

    // 清理临时文件
    this.cleanTemporaryFiles();

    // 停止视频播放
    this.stopCharacterAnimation();
  },

  // ==== 🎞️ 人物动画控制 ====
  startCharacterAnimation() {
    const video = this.data.videoContext;
    if (!video) return;
    try {
      video.seek(0);
      video.play();
      console.log("人物动画开始播放");
    } catch (err) {
      console.warn("启动人物动画失败:", err);
    }
  },

  loopCharacterAnimationOnce() {
    const video = this.data.videoContext;
    if (!video) return;
    try {
      video.seek(0);
      video.play();
      clearTimeout(this._stopTimer);
      this._stopTimer = setTimeout(() => {
        try {
          video.pause();
          console.log("人物动画结束（播放一轮）");
        } catch (e) {}
      }, 3000); // 3秒后暂停，可按视频长度调整
    } catch (err) {
      console.warn("播放动画失败:", err);
    }
  },

  // 当文本输出完成后继续播放视频直到自然结束
  continueCharacterAnimation() {
    const video = this.data.videoContext;
    if (!video) return;
    try {
      // 不做任何操作，让视频自然播放直到结束
      console.log("人物动画继续播放直到自然结束");
    } catch (err) {
      console.warn("继续播放动画失败:", err);
    }
  },

  stopCharacterAnimation() {
    const video = this.data.videoContext;
    if (!video) return;
    try {
      video.pause();
      console.log("人物动画停止");
    } catch (err) {
      console.warn("暂停动画失败:", err);
    }
  },

  // 视频播放结束事件处理
  onVideoEnded() {
    console.log("背景视频播放结束");
    // 可以在这里添加视频播放结束后的处理逻辑
  },

  // ==== 🔊 语音播放功能 ====
  speakText(text) {
    // 调用后端API创建短文本语音合成
    const { userToken, voiceType } = this.data;

    // 文本预处理：将652替换为六五二
    const processedText = this.preprocessText(text);

    // 限制文本长度以符合短文本接口要求
    const maxLength = 50; // 每段最多25个字符，更适合短文本API

    // 将长文本分段处理
    const segments = this.splitTextIntoSegments(processedText, maxLength);

    if (segments.length > 0) {
      console.log(`文本将分${segments.length}段进行语音合成`);
      // 创建一个队列来存储待播放的音频
      this.audioQueue = [];
      this.isAudioPlaying = false;
      // 开始处理第一段文本
      this.processFirstSegment(segments, 0, userToken, voiceType);
    } else {
      wx.showToast({
        title: "无可播放文本",
        icon: "none",
      });
    }
  },

  // 处理第一段文本并开始播放
  processFirstSegment(segments, index, userToken, voiceType) {
    if (index >= segments.length) {
      console.log("没有文本段落需要处理");
      return;
    }

    const currentSegment = segments[index];
    console.log(
      `正在处理第${index + 1}/${segments.length}段文本:`,
      currentSegment
    );

    // 调用短文本语音合成API
    wx.request({
      url: "https://test.uu163yun.com/mapi/Helper/Aip/CreateShortTts",
      method: "POST",
      timeout: 10000,
      header: {
        ...api.mapiHeaders(userToken, { ApiVersion: "5.0" }),
        "content-type": "application/x-www-form-urlencoded",
      },
      data: {
        text: currentSegment,
        voice: voiceType, // 使用当前角色的声音类型
        type: "Baidu",
        format: "mp3",
      },
      success: (res) => {
        console.log(`第${index + 1}段语音合成响应:`, res);
        // 只要返回了base64数据就进行播放，不检查format字段
        if (res.data && res.data.base64) {
          // 语音合成成功，base64转为临时文件播放
          console.log(`第${index + 1}段语音合成完成`);

          // 立即播放第一段音频
          this.playAudioFromBase64(res.data.base64, "mp3", () => {
            // 第一段播放完成后，继续处理并播放下一段
            this.processAndPlayNextSegment(
              segments,
              index + 1,
              userToken,
              voiceType
            );
          });
        } else if (res.data && res.data.result && res.data.reason) {
          // 处理API错误响应
          console.error(`第${index + 1}段语音合成失败：`, res.data.reason);
          wx.showToast({
            title: res.data.reason || "语音合成失败",
            icon: "none",
          });
          // 继续处理下一段
          this.processAndPlayNextSegment(
            segments,
            index + 1,
            userToken,
            voiceType
          );
        } else if (res.data && res.data.result === "exception") {
          // 特别处理操作超时等异常
          const errorMsg = res.data.reason || "操作超时，请稍后重试";
          console.error(`第${index + 1}段语音合成异常：`, errorMsg);
          wx.showToast({
            title: errorMsg,
            icon: "none",
          });
          // 继续处理下一段
          this.processAndPlayNextSegment(
            segments,
            index + 1,
            userToken,
            voiceType
          );
        } else {
          console.error(`第${index + 1}段语音合成失败：`, res);
          wx.showToast({
            title: "语音合成失败",
            icon: "none",
          });
          // 继续处理下一段
          this.processAndPlayNextSegment(
            segments,
            index + 1,
            userToken,
            voiceType
          );
        }
      },
      fail: (err) => {
        console.error(`第${index + 1}段语音合成请求失败：`, err);
        wx.showToast({
          title: "网络请求失败",
          icon: "none",
        });
        // 继续处理下一段
        this.processAndPlayNextSegment(
          segments,
          index + 1,
          userToken,
          voiceType
        );
      },
    });
  },

  // 处理并播放下一段音频
  processAndPlayNextSegment(segments, index, userToken, voiceType) {
    // 检查是否还有段落需要处理
    if (index >= segments.length) {
      console.log("所有文本段落处理完成");
      return;
    }

    const currentSegment = segments[index];
    console.log(
      `正在处理第${index + 1}/${segments.length}段文本:`,
      currentSegment
    );
    const MAPI_BASE = apiConfig.ENV.MAPI_BASE;
    // 调用短文本语音合成API
    wx.request({
      url: `${MAPI_BASE}Helper/Aip/CreateShortTts`,
      method: "POST",
      timeout: 10000, // 10秒超时
      header: {
        ...api.mapiHeaders(userToken, { ApiVersion: "5.0" }),
        "content-type": "application/x-www-form-urlencoded",
      },
      data: {
        text: currentSegment,
        voice: voiceType, // 使用当前角色的声音类型
        type: "Baidu",
        format: "mp3",
      },
      success: (res) => {
        console.log(`第${index + 1}段语音合成响应:`, res);
        // 只要返回了base64数据就进行播放，不检查format字段
        if (res.data && res.data.base64) {
          // 语音合成成功，base64转为临时文件播放
          console.log(`第${index + 1}段语音合成完成`);

          // 播放下一段音频
          this.playAudioFromBase64(res.data.base64, "mp3", () => {
            // 当前段播放完成后，处理下一段
            this.processAndPlayNextSegment(
              segments,
              index + 1,
              userToken,
              voiceType
            );
          });
        } else if (res.data && res.data.result && res.data.reason) {
          // 处理API错误响应
          console.error(`第${index + 1}段语音合成失败：`, res.data.reason);
          wx.showToast({
            title: res.data.reason || "语音合成失败",
            icon: "none",
          });
          // 继续处理下一段
          this.processAndPlayNextSegment(
            segments,
            index + 1,
            userToken,
            voiceType
          );
        } else if (res.data && res.data.result === "exception") {
          // 特别处理操作超时等异常
          const errorMsg = res.data.reason || "操作超时，请稍后重试";
          console.error(`第${index + 1}段语音合成异常：`, errorMsg);
          wx.showToast({
            title: errorMsg,
            icon: "none",
          });
          // 继续处理下一段
          this.processAndPlayNextSegment(
            segments,
            index + 1,
            userToken,
            voiceType
          );
        } else {
          console.error(`第${index + 1}段语音合成失败：`, res);
          wx.showToast({
            title: "语音合成失败",
            icon: "none",
          });
          // 继续处理下一段
          this.processAndPlayNextSegment(
            segments,
            index + 1,
            userToken,
            voiceType
          );
        }
      },
      fail: (err) => {
        console.error(`第${index + 1}段语音合成请求失败：`, err);
        wx.showToast({
          title: "网络请求失败",
          icon: "none",
        });
        // 继续处理下一段
        this.processAndPlayNextSegment(
          segments,
          index + 1,
          userToken,
          voiceType
        );
      },
    });
  },
  

  // 文本预处理：替换特殊字符或数字
  preprocessText(text) {
    if (!text || text.length === 0) return text;

    // 将652替换为六五二
    return text.replace(/652/g, "六五二");
  },

  // 将文本分段
  splitTextIntoSegments(text, maxLength) {
    if (!text || text.length === 0) return [];

    const segments = [];
    // 简单按字符数分割
    for (let i = 0; i < text.length; i += maxLength) {
      segments.push(text.substring(i, i + maxLength));
    }

    return segments;
  },

  // 手动播放/暂停语音
  togglePlayAudio() {
    if (this.data.isPlaying) {
      this.data.audioContext.pause();
    } else {
      // 需要确保已经有音频URL
      this.data.audioContext.play();
    }
  },

  sendChatMessage(content) {
    // 用户发送消息，重置空闲检测
    this.resetIdleDetection();

    const { userToken } = this.data;
    wx.request({
      url: api.endpoints.CHAT_ASK,
      method: "POST",
      header: api.mapiHeaders(userToken),
      data: api.buildChatAsk(content),
      success: (res) => {
        console.log("消息发送成功:", res.data);
        if (res.data && res.data.result === "UNLOGIN") {
          // 未登录情况处理
          this.setData({ isGenerating: false, isTyping: false });
          wx.showToast({
            title: res.data.reason || "请先登录",
            icon: "none",
          });
          return;
        }
        this.setData({ isTyping: true });
      },
      fail: (err) => {
        console.error("消息发送失败:", err);
        // 发送失败时取消生成模式
        this.setData({ isGenerating: false, isTyping: false });
        wx.showToast({
          title: "消息发送失败",
          icon: "none",
        });
      },
      complete: () => {
        this.setData({ isSending: false });
      },
    });
  },

  scrollToBottom() {
    setTimeout(() => {
      this.setData({ scrollTop: 999999 });
    }, 100);
  },

  onUnload() {
    // 标记页面已卸载（全局）
    const app = getApp();
    if (app && app.globalData) app.globalData.isUnloaded = true;

    // 新增：先发送SignOut命令
    const { websocket, isConnected, userId, sessionId, userToken } = this.data;
    if (websocket && isConnected) {
      try {
        websocket.send({
          data: "SignOut",
          success: () => {
            console.log("已发送SignOut命令");
          },
          fail: (err) => {
            console.error("SignOut命令发送失败：", err);
          },
        });
      } catch (e) {
        console.error("SignOut命令异常：", e);
      }
    }

    // 延迟关闭WebSocket和后续操作，确保SignOut发出
    setTimeout(() => {
      if (websocket) {
        websocket.close();
        console.log("WebSocket连接已关闭");
      }
      this.saveChattingHistory();

      // 会话结束接口调用
      if (userId && sessionId) {
        wx.request({
          url: api.endpoints.CHAT_STOP,
          method: "POST",
          header: api.mapiHeaders(userToken, { ApiVersion: "5.0" }),
          data: api.buildChatStop(userId),
          success: (res) => {
            console.log("会话结束接口返回：", res.data);
          },
          fail: (err) => {
            console.error("会话结束接口调用失败：", err);
          },
        });
      }

      // 销毁音频上下文
      if (this.data.audioContext) {
        this.data.audioContext.destroy();
      }

      // 销毁所有活跃的音频上下文并清理临时文件
      if (this.activeAudioContexts) {
        this.activeAudioContexts.forEach((context) => {
          try {
            context.destroy();
          } catch (e) {
            console.warn("销毁音频上下文时出错:", e);
          }
        });
        this.activeAudioContexts = [];
      }

      // 清理所有临时音频文件
      this.cleanTemporaryFiles();

      // 移除storage监听
      wx.onStorageChange(() => {});
    }, 100);
  },
  saveChattingHistory() {
    const { userId, sessionId, messages } = this.data;
    if (messages.length <= 1) return;
    if (!userId || !sessionId) return;

    wx.request({
      url: api.endpoints.HISTORY_SAVE,
      method: "POST",
      header: api.jsonHeaders(this.data.userToken),
      data: { userId, sessionId, messages },
      success: (res) => {
        if (res.data && res.data.code === 200) {
          console.log("聊天记录保存成功");
        }
      },
      fail: (err) => {
        console.error("聊天记录保存失败:", err);
        wx.setStorageSync(`unsaved_chat_${sessionId}`, {
          userId,
          sessionId,
          messages,
        });
      },
    });
  },

  // 语音合成并播放
  speakText(text) {
    // 文本预处理：将652替换为六五二
    const processedText = this.preprocessText(text);

    // 限制文本长度以符合短文本接口要求
    const maxLength = 50; // 每段最多50个字符

    // 将长文本分段处理
    const segments = this.splitTextIntoSegments(processedText, maxLength);

    if (segments.length > 0) {
      console.log(`文本将分${segments.length}段进行语音合成`);
      // 初始化语音播放相关变量
      this.clearAudioQueue(); // 清空之前的音频队列

      // 重置片段计数器
      this.segmentCounter = 0;

      // 开始处理第一段文本
      this.processFirstSegment(segments, 0);
    } else {
      wx.showToast({
        title: "无可播放文本",
        icon: "none",
      });
    }
  },

  // 处理第一段文本并开始播放
  processFirstSegment(segments, index) {
    if (index >= segments.length) {
      console.log("没有文本段落需要处理");
      return;
    }

    const currentSegment = segments[index];
    console.log(
      `正在处理第${index + 1}/${segments.length}段文本:`,
      currentSegment
    );

    // 调用短文本语音合成API
    this.callTTSAPI(currentSegment, index, segments)
      .then((base64) => {
        // 语音合成成功，播放音频
        this.playAudioFromBase64(base64, "mp3", () => {
          // 第一段播放完成后，继续处理并播放下一段
          this.processNextSegment(segments, index + 1);
        });
      })
      .catch((err) => {
        console.error(`第${index + 1}段语音合成失败：`, err);
        wx.showToast({
          title: "语音合成失败",
          icon: "none",
        });
        // 继续处理下一段
        this.processNextSegment(segments, index + 1);
      });
  },

  // 处理并播放下一段音频
  processNextSegment(segments, index) {
    // 检查是否还有段落需要处理
    if (index >= segments.length) {
      console.log("所有文本段落处理完成");
      return;
    }

    const currentSegment = segments[index];
    console.log(
      `正在处理第${index + 1}/${segments.length}段文本:`,
      currentSegment
    );

    // 调用短文本语音合成API
    this.callTTSAPI(currentSegment, index, segments)
      .then((base64) => {
        // 语音合成成功，播放音频
        this.playAudioFromBase64(base64, "mp3", () => {
          // 当前段播放完成后，处理下一段
          this.processNextSegment(segments, index + 1);
        });
      })
      .catch((err) => {
        console.error(`第${index + 1}段语音合成失败：`, err);
        wx.showToast({
          title: "语音合成失败",
          icon: "none",
        });
        // 继续处理下一段
        this.processNextSegment(segments, index + 1);
      });
  },

  // 调用TTS API
  callTTSAPI(text, index, segments) {
    return new Promise((resolve, reject) => {
      const { userToken } = this.data;

      wx.request({
        url: `${apiConfig.ENV.MAPI_BASE}AILantern/Aip/CreateShortTts`,
        method: "POST",
        timeout: 10000,
        header: {
          ...apiConfig.mapiHeaders(userToken, { ApiVersion: "5.0" }),
          "content-type": "application/x-www-form-urlencoded",
        },
        data: {
          text: text,
          voice: this.data.voiceType,
          type: "Baidu",
          format: "mp3",
        },
        success: (res) => {
          if (res.data && res.data.base64) {
            resolve(res.data.base64);
            console.log("语音合成成功", res.data);
          } else if (res.data && res.data.result && res.data.reason) {
            reject(new Error(res.data || "语音合成失败"));
          } else if (res.data && res.data.result === "exception") {
            reject(new Error(res.data || "操作超时，请稍后重试"));
          } else {
            reject(new Error("语音合成失败"));
          }
        },
        fail: (err) => {
          reject(new Error("网络请求失败: " + err.errMsg));
        },
      });
    });
  },
  // 从base64数据播放音频
  playAudioFromBase64(base64Data, format, onComplete) {
    if (!base64Data) {
      console.warn("Base64音频数据为空");
      if (onComplete) onComplete();
      return;
    }

    // 检查base64数据是否有效
    if (base64Data.length < 100) {
      console.warn("Base64音频数据可能无效");
      wx.showToast({
        title: "音频数据无效",
        icon: "none",
      });
      if (onComplete) onComplete();
      return;
    }

    // 检查存储空间并在必要时清理旧文件
    this.checkAndCleanStorage();

    try {
      // 将base64转换为临时文件
      const fs = wx.getFileSystemManager();
      const fileExtension =
        format && format.toLowerCase() === "wav" ? "wav" : "mp3";
      const filePath = `${
        wx.env.USER_DATA_PATH
      }/temp_audio_${Date.now()}_${Math.floor(
        Math.random() * 1000
      )}.${fileExtension}`;

      fs.writeFile({
        filePath: filePath,
        data: base64Data,
        encoding: "base64",
        success: () => {
          console.log("临时音频文件写入成功:", filePath);

          // 使用页面数据中的 audioContext（确保已初始化）
          if (!this.data.audioContext) {
            this.setData({
              audioContext: wx.createInnerAudioContext(),
            });

            // 初始化音频事件监听
            this.initAudioContextEvents();
          }

          // 监听音频播放完成事件
          const onEnded = () => {
            this.data.audioContext.offEnded(onEnded);
            console.log("音频播放完成");

            // 播放完成后删除临时文件
            try {
              fs.unlinkSync(filePath);
              console.log("已删除临时音频文件");
            } catch (e) {
              console.warn("删除临时音频文件失败:", e);
            }

            if (onComplete) onComplete();
          };

          this.data.audioContext.onEnded(onEnded);

          // 播放音频
          this.data.audioContext.src = filePath;
          this.data.audioContext.play();
        },
        fail: (err) => {
          console.error("写入临时音频文件失败：", err);
          // 如果是因为存储空间不足，尝试清理后再重试一次
          if (err.errMsg && err.errMsg.includes("storage limit")) {
            this.cleanTemporaryFiles();
            // 重试一次
            setTimeout(() => {
              fs.writeFile({
                filePath: filePath,
                data: base64Data,
                encoding: "base64",
                success: () => {
                  console.log("临时音频文件写入成功:", filePath);

                  // 使用页面数据中的 audioContext
                  if (!this.data.audioContext) {
                    this.setData({
                      audioContext: wx.createInnerAudioContext(),
                    });

                    // 初始化音频事件监听
                    this.initAudioContextEvents();
                  }

                  // 监听音频播放完成事件
                  const onEnded = () => {
                    this.data.audioContext.offEnded(onEnded);
                    console.log("音频播放完成");

                    // 播放完成后删除临时文件
                    try {
                      fs.unlinkSync(filePath);
                    } catch (e) {
                      console.warn("删除临时音频文件失败:", e);
                    }

                    if (onComplete) onComplete();
                  };

                  this.data.audioContext.onEnded(onEnded);

                  // 播放音频
                  this.data.audioContext.src = filePath;
                  this.data.audioContext.play();
                },
                fail: (err2) => {
                  console.error("第二次尝试写入临时音频文件也失败了：", err2);
                  this.forceCleanAllTemporaryFiles();
                  if (onComplete) onComplete();
                },
              });
            }, 100);
          } else {
            if (onComplete) onComplete();
          }
        },
      });
    } catch (e) {
      console.error("处理音频数据时发生异常：", e);
      wx.showToast({
        title: "音频处理失败",
        icon: "none",
      });
      if (onComplete) onComplete();
    }
  },

  // 初始化音频上下文事件监听
  initAudioContextEvents() {
    if (!this.data.audioContext) return;

    this.data.audioContext.onPlay(() => {
      console.log("音频开始播放");
      // 音频开始播放时切换到说话视频
      this.switchVideoSource("speaking");
    });

    this.data.audioContext.onStop(() => {
      console.log("音频停止");
      // 音频停止时切换回默认视频
      this.switchVideoSource("default");
    });

    this.data.audioContext.onPause(() => {
      console.log("音频暂停");
      // 音频暂停时切换回默认视频
      this.switchVideoSource("default");
    });

    this.data.audioContext.onEnded(() => {
      console.log("音频播放完成");
      // 音频播放完成时切换回默认视频
      this.switchVideoSource("default");
    });

    this.data.audioContext.onError((res) => {
      console.error("音频播放错误", res);
      // 音频出错时切换回默认视频
      this.switchVideoSource("default");
      wx.showToast({
        title: "语音播放失败",
        icon: "none",
      });
    });
  },

  // 检查并清理存储空间
  checkAndCleanStorage() {
    if (!this.lastCleanTime || Date.now() - this.lastCleanTime > 15000) {
      this.cleanTemporaryFiles();
      this.lastCleanTime = Date.now();
    }
  },

  // 清理临时音频文件
  cleanTemporaryFiles() {
    try {
      const fs = wx.getFileSystemManager();
      const fileList = fs.readdirSync(wx.env.USER_DATA_PATH);

      // 删除旧的临时音频文件
      fileList.forEach((file) => {
        if (file.startsWith("temp_audio_")) {
          const filePath = `${wx.env.USER_DATA_PATH}/${file}`;
          try {
            const stat = fs.statSync(filePath);
            // 删除超过30秒的临时文件
            if (stat.isFile() && Date.now() - stat.lastAccessedTime > 30000) {
              fs.unlinkSync(filePath);
              console.log("已删除旧的临时音频文件:", filePath);
            }
          } catch (e) {
            console.warn("检查或删除临时文件失败:", filePath, e);
          }
        }
      });
    } catch (e) {
      console.warn("清理临时文件时出错:", e);
    }
  },

  // 清空音频队列
  clearAudioQueue() {
    // 停止所有活跃的音频上下文
    if (this.audioContexts) {
      this.audioContexts.forEach((context) => {
        try {
          context.stop();
          context.destroy();
        } catch (e) {
          console.warn("停止音频上下文时出错:", e);
        }
      });
      this.audioContexts = [];
    }
  },

  // 文本预处理：替换特殊字符或数字
  preprocessText(text) {
    if (!text || text.length === 0) return text;

    // 将652替换为六五二
    return text.replace(/652/g, "六五二");
  },

  // 将文本分段
  splitTextIntoSegments(text, maxLength) {
    if (!text || text.length === 0) return [];

    const segments = [];
    // 简单按字符数分割
    for (let i = 0; i < text.length; i += maxLength) {
      segments.push(text.substring(i, i + maxLength));
    }

    return segments;
  },
  // 新增：从后端请求故事列表，失败时回退到样例数据
  fetchStories() {
    const backendUrl = apiConfig.ENV.API_BASE;
    const apiUrl = `${backendUrl}api/story/list`;
    const sampleData = {
      code: 200,
      data: [
        {
          id: 0,
          title: "",
          content: "",
          createTime: "",
        },
      ],
    };

    wx.request({
      url: apiUrl,
      method: "GET",
      success: (res) => {
        if (res.data && res.data.code === 200 && Array.isArray(res.data.data)) {
          console.log(res.data.data);
          this.setData({ storyList: res.data.data });
          this.setData({
            displayStoryList: this.data.storyList.slice(0, 3).map((item) => ({
              ...item,
              desc: "点击查看完整故事内容",
            })),
          });
        } else {
          console.warn("fetchStories: API 返回异常，使用本地样例数据");
          this.setData({ storyList: sampleData.data });
        }
      },
      fail: () => {
        console.warn("fetchStories: 请求失败，使用本地样例数据");
        this.setData({ storyList: sampleData.data });
      },
    });
  },

  // 选择列表项
  selectItem(e) {
    const id = e.currentTarget.dataset.id;
    const tab = this.data.activeTab;

    if (tab === "story") {
      // 先在原始故事列表中查找
      let idx = this.data.storyList.findIndex((it) => it.id === id);
      if (idx !== -1) {
        this.openStoryModal(idx);
        return;
      }

      // 如果没找到，则在生成的故事列表中查找
      idx = this.data.generatedStories.findIndex((it) => it.id === id);
      if (idx !== -1) {
        this.openGeneratedStoryModal(idx);
        return;
      }
    }
  },

  openStoryModal(index) {
    const item = this.data.storyList[index] || {};
    // 停止任何图片轮播，避免冲突
    if (this._photoTimer) {
      clearInterval(this._photoTimer);
      this._photoTimer = null;
      this.setData({ "photoModal.slideshow": false });
    }

    // 先显示骨架面板
    this.setData({
      "storyModal.show": true,
      "storyModal.index": index,
      "storyModal.data.title": item.title || "加载中...",
      "storyModal.data.content": "正在加载故事内容...",
      "storyModal.isPlaying": false,
    });

    // 异步尝试拉取详情 API（示例接口），失败回退本地样例
    const backendUrl = apiConfig.ENV.backendUrl;
    const apiUrl = `${backendUrl}/api/story/${item.id || ""}`;
    wx.request({
      url: apiUrl,
      method: "GET",
      success: (res) => {
        if (res.data && res.data.code === 200 && res.data.data) {
          const d = res.data.data;
          this.setData({
            "storyModal.data": {
              id: d.id,
              title: d.title,
              content: d.content,
              audio: d.audio || "",
            },
          });
          // 如果有音频，准备 inner audio
          if (d.audio) {
            this._prepareStoryAudio(d.audio);
          }
        } else {
          // 回退：使用本地 content（若没有，可显示提示）
          this.setData({
            "storyModal.data.content": item.detail || "暂无详细内容。",
          });
        }
      },
      fail: () => {
        this.setData({
          "storyModal.data.content":
            item.detail || "暂无详细内容（网络异常）。",
        });
      },
    });
  },

  // 打开AI生成的故事详情
  openGeneratedStoryModal(index) {
    const item = this.data.generatedStories[index] || {};

    // 停止任何图片轮播，避免冲突
    if (this._photoTimer) {
      clearInterval(this._photoTimer);
      this._photoTimer = null;
      this.setData({ "photoModal.slideshow": false });
    }

    this.setData({
      "storyModal.show": true,
      "storyModal.index": index + 1000, // 区分原始故事和生成故事的索引
      "storyModal.data": {
        id: item.id,
        title: item.title || "生成故事",
        content: item.content || "暂无内容",
        audio: "",
      },
      "storyModal.isPlaying": false,
    });
  },

  // 使用 InnerAudioContext 创建/准备音频
  _prepareStoryAudio(src) {
    try {
      if (!this._storyAudio) {
        this._storyAudio = wx.createInnerAudioContext();
        this._storyAudio.autoplay = false;
        this._storyAudio.loop = false;
        this._storyAudio.onPlay(() => {
          this.setData({
            "storyModal.isPlaying": true,
            storyAudioLoading: false,
          });
        });
        this._storyAudio.onPause(() => {
          this.setData({ "storyModal.isPlaying": false });
        });
        this._storyAudio.onEnded(() => {
          this.setData({ "storyModal.isPlaying": false });
        });
        this._storyAudio.onWaiting &&
          this._storyAudio.onWaiting(() => {
            this.setData({ storyAudioLoading: true });
          });
        this._storyAudio.onCanplay &&
          this._storyAudio.onCanplay(() => {
            this.setData({ storyAudioLoading: false });
          });
        this._storyAudio.onError((err) => {
          console.error("storyAudio error", err);
          this.setData({
            "storyModal.isPlaying": false,
            storyAudioLoading: false,
          });
          wx.showToast({ title: "音频播放出错", icon: "none" });
        });
      }
      this._storyAudio.src = src || "";
    } catch (e) {
      console.error("prepareStoryAudio error", e);
    }
  },

  // 根据配置构建获取真实 MP3 直链的接口地址
  _getApiBase() {
    return apiConfig.ENV.backendUrl;
  },
  _getMp3Endpoint(id) {
    return `${this._getApiBase()}/api/story/${id}/mp3`;
  },
  _fetchMp3RealUrl(id) {
    return new Promise((resolve, reject) => {
      if (id === undefined || id === null) {
        reject(new Error("INVALID_ID"));
        return;
      }
      wx.request({
        url: this._getMp3Endpoint(id),
        method: "GET",
        success: (res) => {
          const url =
            res &&
            res.data &&
            res.data.code === 200 &&
            Array.isArray(res.data.data) &&
            res.data.data[0]
              ? res.data.data[0]
              : "";
          if (url) resolve(url);
          else reject(new Error("EMPTY_URL"));
        },
        fail: (err) => reject(err),
      });
    });
  },

  // 切换故事朗读：首次点击会去后端拿直链并缓存到 storyModal.data.audio
  toggleStoryAudio() {
    const id =
      this.data.storyModal && this.data.storyModal.data
        ? this.data.storyModal.data.id
        : null;
    let audioSrc = this.data.storyModal.data && this.data.storyModal.data.audio;

    // 若正在播放，点击则暂停
    if (this.data.storyModal.isPlaying) {
      try {
        this._storyAudio && this._storyAudio.pause();
      } catch (e) {}
      this.setData({ "storyModal.isPlaying": false });
      return;
    }

    // 未播放：若已有缓存直链则直接播放
    if (audioSrc) {
      if (!this._storyAudio) this._prepareStoryAudio(audioSrc);
      try {
        this.setData({ storyAudioLoading: true });
        this._storyAudio.play();
      } catch (e) {
        this.setData({ storyAudioLoading: false });
        wx.showToast({ title: "音频启动失败", icon: "none" });
      }
      return;
    }

    // 无缓存：点击时发起请求获取真实直链
    if (id === undefined || id === null) {
      wx.showToast({ title: "缺少音频资源", icon: "none" });
      return;
    }
    this.setData({ storyAudioLoading: true });
    this._fetchMp3RealUrl(id)
      .then((realUrl) => {
        this.setData({ "storyModal.data.audio": realUrl });
        // 准备并播放
        if (!this._storyAudio) this._prepareStoryAudio(realUrl);
        else this._prepareStoryAudio(realUrl);
        try {
          this._storyAudio.play();
        } catch (e) {
          this.setData({ storyAudioLoading: false });
          wx.showToast({ title: "音频启动失败", icon: "none" });
        }
      })
      .catch((err) => {
        console.error("fetch mp3 url error", err);
        this.setData({ storyAudioLoading: false });
        wx.showToast({ title: "获取音频链接失败", icon: "none" });
      });
  },

  closeStoryModal() {
    // 停止并销毁 InnerAudioContext（如在播放）
    try {
      if (this._storyAudio) {
        try {
          this._storyAudio.stop();
        } catch (e) {}
        this._storyAudio.offPlay && this._storyAudio.offPlay();
        this._storyAudio.offPause && this._storyAudio.offPause();
        this._storyAudio.offEnded && this._storyAudio.offEnded();
        this._storyAudio.offError && this._storyAudio.offError();
        try {
          this._storyAudio.destroy();
        } catch (e) {}
        this._storyAudio = null;
      }
    } catch (e) {
      console.warn("closeStoryModal audio cleanup error", e);
    }

    this.setData({
      "storyModal.show": false,
      "storyModal.isPlaying": false,
    });
  },
  nextStory() {
    // 检查是否为原始故事还是生成故事
    const currentIndex = this.data.storyModal.index;
    if (currentIndex < 1000) {
      // 原始故事
      const next = (currentIndex + 1) % this.data.storyList.length;
      this.openStoryModal(next);
    } else {
      // 生成故事
      const actualIndex = currentIndex - 1000;
      const next = (actualIndex + 1) % this.data.generatedStories.length;
      this.openGeneratedStoryModal(next);
    }
  },
  prevStory() {
    // 检查是否为原始故事还是生成故事
    const currentIndex = this.data.storyModal.index;
    if (currentIndex < 1000) {
      // 原始故事
      const prev =
        (currentIndex - 1 + this.data.storyList.length) %
        this.data.storyList.length;
      this.openStoryModal(prev);
    } else {
      // 生成故事
      const actualIndex = currentIndex - 1000;
      const prev =
        (actualIndex - 1 + this.data.generatedStories.length) %
        this.data.generatedStories.length;
      this.openGeneratedStoryModal(prev);
    }
  },

  toggleSlideshow() {
    const s = !this.data.photoModal.slideshow;
    this.setData({ "photoModal.slideshow": s });
    if (s) {
      // 自动轮播：简单实现
      this._photoTimer = setInterval(() => {
        this.nextPhoto();
      }, 2500);
    } else {
      if (this._photoTimer) {
        clearInterval(this._photoTimer);
        this._photoTimer = null;
      }
    }
  },
  toggleInputMode() {
    this.setData({
      isVoiceMode: !this.data.isVoiceMode,
    });
  },
  downloadBook() {
    wx.showToast({ title: "开始下载（示例）", icon: "none" });
    // 实际实现略
  },
  startRecording() {
    this.setData({
      recording: true,
    });
    console.log("开始录音");
    
    // 打断当前正在播放的语音
    this.interruptCurrentTask();
    
    // 实际录音逻辑
    this.recorderManager = wx.getRecorderManager();
    this.recorderManager.start({
      format: "wav",
      sampleRate: 16000,
      numberOfChannels: 1,
      encodeBitRate: 48000,
    });
  },

  // 停止录音
  stopRecording() {
    this.setData({
      recording: false,
      isTranscribing: true, // 设置转写状态
    });
    console.log("停止录音");

    // 停止录音并获取音频文件
    if (this.recorderManager) {
      this.recorderManager.stop();
      this.recorderManager.onStop((res) => {
        console.log("录音文件路径:", res.tempFilePath);
        if (res.duration < 1000) {
          wx.showToast({
            title: "录音时间太短",
            icon: "none",
          });
          this.setData({
            isTranscribing: false,
          });
          return;
        }
        // // 检查用户是否已登录
        // if (!this.checkUserLoggedIn()) {
        //   wx.showToast({
        //     title: "请先登录",
        //     icon: "none",
        //   });
        //   this.setData({
        //     isTranscribing: false,
        //   });
        //   return;
        // }

        // 调用语音转文本API
        this.transcribeAudio(res.tempFilePath)
          .then((transcribedText) => {
            // 将转写结果设置到 userInput
            this.setData({
              userInput: transcribedText,
              isTranscribing: false,
            });
          })
          .catch((err) => {
            console.error("语音转写失败:", err);
            wx.showToast({
              title: "语音转写失败: " + err.message,
              icon: "none",
            });
            this.setData({
              isTranscribing: false,
            });
          });
      });
    }
  },
  transcribeAudio(audioFilePath) {
    return new Promise((resolve, reject) => {
      // 直接读取音频文件为base64格式
      wx.getFileSystemManager().readFile({
        filePath: audioFilePath,
        encoding: "base64", // 直接读取为base64格式
        success: (res) => {
          const base64 = res.data;
          console.log("音频转base64成功，数据长度：", base64.length);

          // 获取文件长度
          const fs = wx.getFileSystemManager();
          fs.readFile({
            filePath: audioFilePath,
            success: (lenRes) => {
              const len = lenRes.data.byteLength;
              console.log("音频文件长度：", len);
              // 获取用户信息并发送请求
              this.processTranscribeRequest(base64, len)
                .then(resolve)
                .catch(reject);
            },
            fail: (lenErr) => {
              console.error("获取文件长度失败", lenErr);
              reject(new Error("获取文件信息失败: " + lenErr.errMsg));
            },
          });
        },
        fail: (err) => {
          console.error("音频文件读取失败", err);
        },
      });
    });
  },
  // 处理语音识别请求
  processTranscribeRequest(base64, len) {
    return new Promise((resolve, reject) => {
      const { userToken, userId } = this.data;
      const fallbackUserToken = wx.getStorageSync("loginResult")?.userToken;
      const fallbackUserId =
        wx.getStorageSync("userInfo")?.userId ||
        wx.getStorageSync("userInfo")?.openId;

      const finalUserToken = userToken || fallbackUserToken;
      const finalUserId = userId || fallbackUserId;
      if (!finalUserToken) {
        console.error("未获取到用户令牌");
        reject(new Error("未获取到用户令牌"));
        return;
      }

      if (!finalUserId) {
        console.error("未获取到用户ID");
        reject(new Error("未获取到用户ID"));
        return;
      }
      const requestData = {
        type: "Baidu",
        base64: base64,
        rate: 16000,
        len: len,
        format: "wav",
        userGuid: finalUserId,
        endpointCode: "Suse652-1",
        endpointVersion: "1.0.0",
        dev_pid: 1537,
      };

      wx.request({
        url: 'https://test.uu163yun.com/mapi/Helper/Aip/Asr',
        method: "POST",
        header: {
          ...apiConfig.mapiHeaders(finalUserToken, { ApiVersion: "5.0" }),
          "content-type": "application/x-www-form-urlencoded",
        },
        data: requestData,
        success: (res) => {
          console.log("语音识别响应:", res);
          if (res.data && res.data.texts) {
            console.log("语音识别成功，文本内容:", res.data.texts);
            resolve(res.data.texts);
          } else if (res.data && res.data.result === "NotRecongnized") {
            const errorMsg = res.data.reason || "语音识别失败";
            reject(new Error(errorMsg));
          } else {
            reject(
              new Error("语音识别失败: " + (res.data.message || "未知错误"))
            );
          }
        },
        fail: (err) => {
          console.error("语音识别请求失败", err);
          reject(new Error("网络请求失败: " + err.errMsg));
        },
      });
    });
  },
  // 取消录音
  cancelRecording() {
    this.setData({
      recording: false,
    });
    console.log("取消录音");
    // 清理录音资源
    if (this.recorderManager) {
      this.recorderManager.stop();
    }
  },
  checkUserLoggedIn() {
    const { userToken, userId } = this.data;
    const hasToken = !!userToken;
    const hasUserId = !!userId;

    if (!hasToken || !hasUserId) {
      console.warn("用户未完全登录", { hasToken, hasUserId });
      // 尝试重新加载登录信息
      this.loadLoginInfo();

      // 再次检查
      const { userToken: newToken, userId: newId } = this.data;
      return !!newToken && !!newId;
    }

    return true;
  },
  // 加载登录信息
  loadLoginInfo() {
    try {
      const loginResult = wx.getStorageSync("loginResult");
      if (loginResult) {
        this.setData({
          userToken: loginResult.userToken,
          userId: loginResult.userId,
        });
        console.log("成功加载登录信息");
      } else {
        console.log("未找到 loginResult，尝试从 userInfo 获取"); // 改为 info 级别
        const userinfo = wx.getStorageSync("userInfo");
        if (userinfo) {
          this.setData({
            userId: userinfo.userId || userinfo.openId,
          });
          console.log("从 userInfo 成功获取用户信息");
        } else {
          console.log("登录失败");
        }
      }
    } catch (e) {
      console.error("加载登录信息失败:", e);
    }
  },
  onLoad() {
    const app = getApp();
    const gender = app.globalData.gender || "female";
    const imgBaseUrl = apiConfig.ENV.imgBaseUrl;
    const videoBaseUrl = apiConfig.ENV.videoBaseUrl;
    const iconBaseUrl = apiConfig.ENV.iconBaseUrl;
    const audioContext = wx.createInnerAudioContext();
    const voiceType=gender === "male" ? 5003 : 0;
    if (videoBaseUrl && iconBaseUrl) {
      // 根据性别设置不同的视频源
      const videoSrc =
        gender === "male"
          ? videoBaseUrl + "male-waving1.mp4"
          : videoBaseUrl + "female_waving2.mp4";

      this.setData({
        // 设置默认视频，使用 apiConfig 中定义的 videoBaseUrl
        currentVideoSrc: videoSrc,
        storyRecord: iconBaseUrl + "story_record.png",
        storyMore: iconBaseUrl + "story_more.png",
        audioContext: audioContext,
        gender: gender, // 保存当前性别设置
        voiceType: voiceType,
        robotAvatar:
          gender === "male"
            ? imgBaseUrl + "avatar_male.png"
            : imgBaseUrl + "avatar_female.png",
      });
    } else {
      console.error("错误：未获取到BaseUrl");
    }
    this.initDisplayData();
    this.initAudioContextEvents();
    this.loadLoginInfo();
    this.initTimeDisplay();
    // 初始化WebSocket连接
    setTimeout(() => {
      this.connectWebSocket();
    }, 1000);

    const userinfo = wx.getStorageSync("userInfo");
    const { userToken, userId } = this.data;
    console.log(userToken, userId);
    if (userinfo === null) {
      wx.navigateTo({
        url: "/pages/welcome/welcome",
      });
    } else {
    }
  },
  generateUUID() {
    return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(
      /[xy]/g,
      function (c) {
        const r = (Math.random() * 16) | 0;
        const v = c === "x" ? r : (r & 0x3) | 0x8;
        return v.toString(16);
      }
    );
  },
  forceCleanAllTemporaryFiles() {
    try {
      const fs = wx.getFileSystemManager();
      const fileList = fs.readdirSync(wx.env.USER_DATA_PATH);

      // 删除所有临时音频文件
      fileList.forEach((file) => {
        if (file.startsWith("temp_audio_")) {
          const filePath = `${wx.env.USER_DATA_PATH}/${file}`;
          try {
            fs.unlinkSync(filePath);
            console.log("强制删除临时音频文件:", filePath);
          } catch (e) {
            console.warn("强制删除临时文件失败:", filePath, e);
          }
        }
      });
    } catch (e) {
      console.warn("强制清理临时文件时出错:", e);
    }
  },
  onReady() {
    // 页面加载完成后播放视频
    this.playVideo();

    // 初始化空闲检测
    this.initIdleDetection();

  },

  // 播放视频
  playVideo() {
    this.videoContext = wx.createVideoContext("bgVideo", this);
    if (this.videoContext) {
      try {
        this.videoContext.play();
      } catch (e) {
        console.warn("视频播放失败:", e);
      }
    }
  },

  // 视频播放结束
  onVideoEnded() {},
  // 页面卸载
  onUnload() {
    // 清理空闲检测定时器
    if (this.idleTimer) {
      clearTimeout(this.idleTimer);
    }

    // 清理时间更新定时器
    if (this.timeUpdateInterval) {
      clearInterval(this.timeUpdateInterval);
    }
    
    // 停止所有音频播放并清理临时文件
    this.interruptCurrentTask();
    
    // 发送SignOut命令
    const { websocket, isConnected, userId, sessionId, userToken } = this.data;
    if (websocket && isConnected) {
      try {
        websocket.send({
          data: "SignOut",
          success: () => {
            console.log("已发送SignOut命令");
          },
          fail: (err) => {
            console.error("SignOut命令发送失败：", err);
          },
        });
      } catch (e) {
        console.error("SignOut命令异常：", e);
      }
    }

    // 延迟关闭WebSocket和后续操作，确保SignOut发出
    setTimeout(() => {
      if (websocket) {
        websocket.close();
        console.log("WebSocket连接已关闭");
      }
    }, 100);
  },
  // 初始化展示数据
  initDisplayData() {
    // // 初始化老故事展示数据（只显示前3个）
    // this.fetchStories();
  },

  // 查看更多内容
  showMoreContent() {
    wx.navigateTo({ url: "/pages/storylist/storylist" });
  },

  /// AI生成故事相关方法
  generateStory() {
    const prompt = this.data.userInput.trim();
    if (!prompt) {
      wx.showToast({
        title: "请输入提示词",
        icon: "none",
      });
      return;
    }

    // 构造完整的提示词
    const fullPrompt = `你现在是一位故事专家，请您结合四川轻化工大学的652精神，结合${prompt}主题生成一段不超过500字的故事`;

    // 确保WebSocket连接
    if (!this.data.isConnected) {
      this.connectWebSocket();
    }

    this.setData({
      isGenerating: true,
    });

    // 发送消息到WebSocket
    this.sendChatMessage(fullPrompt);
  },

  // 在 onInput 方法中更新
  onInput(e) {
    this.setData({
      userInput: e.detail.value,
    });

    // 用户有输入操作，重置空闲检测
    this.resetIdleDetection();
  },

  // 选择建议提示词
  selectSuggestion(e) {
    const suggestion = e.currentTarget.dataset.suggestion;
    this.setData({
      userInput: suggestion,
    });

    // 用户选择了建议提示词，重置空闲检测
    this.resetIdleDetection();
  },
});
